package com.jushu.storbox.util.image;

import java.io.File;
import java.util.Random;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.support.v4.util.LruCache;

import com.jushu.storbox.util.LogUtil;
import com.jushu.storbox.util.image.PathHolder.ImageSourceState;


public class ImageCache extends LruCache<PathHolder, Bitmap> {

	private static final String TAG = ImageCache.class.getSimpleName();
	
	Context context = null;

    private Random random = new Random();
    
	public interface ImageLoader{

		/**
		 * @param item
		 */
		void onBeforeLoad(PathHolder item);

		/**
		 * @param item
		 * @param bitmap
		 */
		void onLoadding(PathHolder item, int progress);
		
		/**
		 * @param item
		 * @param bitmap
		 */
		void onLoadSuccess(PathHolder item, Bitmap bitmap);
		
		/**
		 * @param item
		 * @param e
		 */
		void onLoadFail(PathHolder item, Throwable e);

		/**
		 * @param path
		 * @param bitmap
		 */
		void onDestoryed(PathHolder item);
		
	}
	
	private ImageLoader imageLoader = null;

	private int imgWidht;

	private int imgHeight;
	
	public ImageCache(Context context, int maxSize, int imgWidht, int imgHeight) {
		super(maxSize);
		this.context = context;
		this.imgWidht = imgWidht;
		this.imgHeight = imgHeight;
	}

	@Override
	protected Bitmap create(PathHolder item) {
		LogUtil.i(TAG,"decode bitmap from path");
		Bitmap bmp = null;
		if(imageLoader != null) {
			imageLoader.onBeforeLoad(item);
		}

		item.setImageState(ImageSourceState.LOAD_STATE_WHERE_LOADDING);
		if(imageLoader != null) {
			imageLoader.onLoadding(item,getRandomProgress(0,10));
		}
		
		try {
	        BitmapFactory.Options opt = new BitmapFactory.Options();
	        opt.inPreferredConfig = Config.ARGB_8888;
	        opt.inPurgeable = true;
	        opt.inInputShareable = true;
	        if(imageLoader != null) {
	        	imageLoader.onLoadding(item,getRandomProgress(20,40));
	        }
	        bmp = createImageThumbnail(item.getFilePath());
	        if(bmp != null) {
				item.setImageState(ImageSourceState.LOAD_STATE_WHERE_MEMERY);
				if(imageLoader != null) {
					imageLoader.onLoadding(item,getRandomProgress(50,100));
					imageLoader.onLoadSuccess(item, bmp);
				}
	        } else {
				imageLoader.onLoadFail(item, new Exception("load image failed!"));
	        }
		} catch (OutOfMemoryError e) {
			LogUtil.e(TAG,e.getMessage());
			if(imageLoader != null) {
				imageLoader.onLoadFail(item, e);
			}
		} catch (Exception e) {
			LogUtil.e(TAG,e.getMessage());
			if(imageLoader != null) {
				imageLoader.onLoadFail(item, e);
			}
		}
		return bmp;
	}

	@Override
	protected void entryRemoved(boolean evicted, PathHolder item, Bitmap oldValue,
			Bitmap newValue) {
		LogUtil.i(TAG,"remove bitmap from path");
		distoryOldBitmap(item, oldValue);
	}

	@Override
	protected int sizeOf(PathHolder item, Bitmap value) {
		return getBitmapSize(value);
	}
	
	public void loadding(PathHolder item) {
		Bitmap bitmap = this.get(item);
		if(imageLoader != null) {
			if(bitmap != null && !bitmap.isRecycled()) {
				LogUtil.d(TAG, "success to get bitmap from cache");
				imageLoader.onLoadSuccess(item,bitmap);
			} else if(bitmap == null){
				LogUtil.e(TAG,"current bitmap is null.");
				imageLoader.onLoadFail(item, new Exception("current bitmap is null."));
			} else {
				LogUtil.e(TAG,"bitmap is recycled!");
				imageLoader.onLoadFail(item, new Exception("bitmap is recycled!"));
			}
		} else {
			LogUtil.e(TAG,"imageLoader instance is null");
		}
	}
	
	public Bitmap createImageThumbnail(String filePath)
    {
        File file = new File(filePath);
        if (!file.exists())
        {
            return null;
        }
        Bitmap bitmap = null;
        BitmapFactory.Options opts = new BitmapFactory.Options();
        opts.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(filePath, opts);
        opts.inSampleSize = computeSampleSize(opts, imgWidht, imgHeight);// 128*128
        opts.inJustDecodeBounds = false;
        opts.inPreferredConfig = Bitmap.Config.RGB_565;
        opts.inPurgeable = true;
        opts.inInputShareable = true;
        opts.inTempStorage = new byte[12 * 1024];
        try
        {
            bitmap = BitmapFactory.decodeFile(filePath, opts);
            opts.inTempStorage = null;
            if (null != bitmap)
            {
                int degree = BitmapUtil.getBitmapDegree(filePath);
                if (0 != degree)
                {
                    bitmap = BitmapUtil.rotateBitmapByDegree(bitmap, degree);
                }
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return bitmap;
    }
	
	private int computeSampleSize(BitmapFactory.Options options, int width, int height)
    {
        int initialSize = computeInitialSampleSize(options, width, height);
        int roundedSize = initialSize;
//        if (initialSize <= 8)
//        {
//            roundedSize = 1;
//            while (roundedSize < initialSize)
//            {
//                roundedSize <<= 1;
//            }
//            if(roundedSize !=) {
//            	roundedSize >>= 1;
//            }
//        }
//        else
//        {
//            roundedSize = (initialSize + 7) / 8 * 8;
//        }
        return roundedSize;
    }
    
    private int computeInitialSampleSize(BitmapFactory.Options options,int width, int height)
    {
        float w = options.outWidth;
        float h = options.outHeight;
        int sampleSize = 1;
        if(w > width || h > height) {
	        int tempWidth = Math.round(w / width);
	        int tempHeight = Math.round(h / height);
        	sampleSize = tempWidth > tempHeight ? tempHeight:tempWidth;
        }
        return sampleSize;
    }
	
	private int getRandomProgress(int start, int end)
    {
        int progress = 0;
        try
        {
            if (null == random)
            {
                random = new Random();
            }
            progress = (start + random.nextInt(end - start));
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return progress;
    }
	
	public int getBitmapSize(Bitmap bitmap) {
		if(bitmap == null) {
			return 0;
		}
		int bmpSize = bitmap.getWidth() * bitmap.getHeight() * getBitOfPixture(bitmap);
		return bmpSize;
	}

	private int getBitOfPixture(Bitmap bitmap) {
		int retSize = 32;
		Config cfg = bitmap.getConfig();
		if(cfg != null) {
			switch(cfg){
				case ARGB_8888:
					retSize = 32;
					break;
					
				case ARGB_4444:
					retSize = 16;
					break;
					
				case RGB_565:
					retSize = 16;
					break;
					
				case ALPHA_8:
					retSize = 8;
					break;
				default:
					retSize = 32;
			}
		} else {
			retSize = 16;
		}
		return retSize;
	}

	private void distoryOldBitmap(PathHolder item, Bitmap oldValue) {
		LogUtil.i(TAG,"distory bitmap");
		if(oldValue != null && !oldValue.isRecycled()){
			oldValue.recycle();
			item.setImageState(ImageSourceState.LOAD_STATE_WHERE_LOCAL);
			if(imageLoader != null) {
				imageLoader.onDestoryed(item);
			}
			oldValue = null;
		}
	}
	
	public ImageLoader getImageLoader() {
		return imageLoader;
	}

	public void setImageLoader(ImageLoader imageLoader) {
		this.imageLoader = imageLoader;
	}
}
